package com.peas.platform.module.icims.expenditure.expenses.domain.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.peas.platform.framework.mybatisplus.domain.BaseDomainImpl;
import com.peas.platform.framework.mybatisplus.repository.BaseRepository;
import com.peas.platform.framework.mybatisplus.utils.PageUtil;
import com.peas.platform.module.icims.base.sys.enums.CommonEnableDisable;
import com.peas.platform.module.icims.base.sys.enums.CommonYesNo;
import com.peas.platform.module.icims.base.sys.service.SequenceService;
import com.peas.platform.module.icims.expenditure.basal.dto.ExpenditureAccountDto;
import com.peas.platform.module.icims.expenditure.basal.enums.ExpenditureAccountType;
import com.peas.platform.module.icims.expenditure.basal.service.ExpenditureAccountService;
import com.peas.platform.module.icims.expenditure.expenses.adapter.repository.ExpenditureReimbursementRepository;
import com.peas.platform.module.icims.expenditure.expenses.adapter.repository.po.ExpenditureReimbursementPo;
import com.peas.platform.module.icims.expenditure.expenses.api.req.ExpenditureReimbursementReq;
import com.peas.platform.module.icims.expenditure.expenses.domain.ExpenditureReimbursementDomain;
import com.peas.platform.module.icims.expenditure.expenses.dto.*;
import com.peas.platform.module.icims.expenditure.expenses.service.*;
import com.peas.platform.module.icims.expenditure.kpis.dto.ExpenditureKpiDto;
import com.peas.platform.module.icims.expenditure.kpis.service.ExpenditureKpiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ExpenditureReimbursementDomainImpl extends BaseDomainImpl<ExpenditureReimbursementDto, ExpenditureReimbursementPo> implements ExpenditureReimbursementDomain {

    @Resource
    private ExpenditureReimbursementRepository expenditureReimbursementRepository;
    @Resource
    private SequenceService sequenceService;
    @Resource
    private ExpenditureReimbursementTravelService expenditureReimbursementTravelService;
    @Resource
    private ExpenditureReimbursementContractService expenditureReimbursementContractService;
    @Resource
    private ExpenditureReimbursementMeetingService expenditureReimbursementMeetingService;
    @Resource
    private ExpenditureReimbursementTrainingService expenditureReimbursementTrainingService;
    @Resource
    private ExpenditureReimbursementTrafficService expenditureReimbursementTrafficService;
    @Resource
    private ExpenditureReimbursementAbroadService expenditureReimbursementAbroadService;
    @Resource
    private ExpenditureReimbursementOtherService expenditureReimbursementOtherService;
    @Resource
    private ExpenditureReimbursementItemFileService expenditureReimbursementItemFileService;
    @Resource
    private ExpenditureReimbursementPayService expenditureReimbursementPayService;
    @Resource
    private ExpenditureReimbursementPayeeService expenditureReimbursementPayeeService;
    @Resource
    private ExpenditureReimbursementFileService expenditureReimbursementFileService;
    @Resource
    private ExpenditureKpiService expenditureKpiService;
    @Resource
    private ExpenditureAccountService expenditureAccountService;

    @Override
    public BaseRepository<ExpenditureReimbursementPo> getMapper() {
        return expenditureReimbursementRepository;
    }

    @Override
    public Class<? extends BaseRepository<ExpenditureReimbursementPo>> getRepositoryClass() {
        return ExpenditureReimbursementRepository.class;
    }

    @Transactional
    @Override
    public int save(ExpenditureReimbursementDto dto) {
        if (StrUtil.isBlank(dto.getReimbursementCode())) {
            String code = sequenceService.genSequence("expenditure", "ExpenditureReimbursementDto", "ERD", 4, 1);
            dto.setReimbursementCode(code);
        }
        int result = super.save(dto);
        this.checkRepetition("reimbursementCode", dto.getReimbursementCode());
        //回写指标单
        ExpenditureKpiDto kpi = expenditureKpiService.getById(dto.getExpenditureKpiId());
        if (!StrUtil.equals(CommonYesNo.yes.getKey(), kpi.getIsBegin())) {
            kpi.setIsBegin(CommonYesNo.yes.getKey());
            expenditureKpiService.updateById(kpi);
        }
        return result;
    }

    @Transactional
    @Override
    public int updateById(ExpenditureReimbursementDto dto) {
        int result = super.updateById(dto);
        this.checkRepetition("reimbursementCode", dto.getReimbursementCode());
        //回写指标单
        ExpenditureKpiDto kpi = expenditureKpiService.getById(dto.getExpenditureKpiId());
        if (!StrUtil.equals(CommonYesNo.yes.getKey(), kpi.getIsBegin())) {
            kpi.setIsBegin(CommonYesNo.yes.getKey());
            expenditureKpiService.updateById(kpi);
        }
        return result;
    }

    @Transactional
    @Override
    public int removeById(Serializable id) {
        int result = super.removeById(id);
        // travels
        List<ExpenditureReimbursementTravelDto> travels = expenditureReimbursementTravelService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementTravelService.removeBatchByList(travels);
        // contracts
        List<ExpenditureReimbursementContractDto> contracts = expenditureReimbursementContractService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementContractService.removeBatchByList(contracts);
        // meetings
        List<ExpenditureReimbursementMeetingDto> meetings = expenditureReimbursementMeetingService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementMeetingService.removeBatchByList(meetings);
        // trainings
        List<ExpenditureReimbursementTrainingDto> trainings = expenditureReimbursementTrainingService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementTrainingService.removeBatchByList(trainings);
        // traffics
        List<ExpenditureReimbursementTrafficDto> traffics = expenditureReimbursementTrafficService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementTrafficService.removeBatchByList(traffics);
        // abroads
        List<ExpenditureReimbursementAbroadDto> abroads = expenditureReimbursementAbroadService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementAbroadService.removeBatchByList(abroads);
        // others
        List<ExpenditureReimbursementOtherDto> others = expenditureReimbursementOtherService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementOtherService.removeBatchByList(others);
        // itemFiles
        List<ExpenditureReimbursementItemFileDto> itemFiles = expenditureReimbursementItemFileService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementItemFileService.removeBatchByList(itemFiles);
        // pays
        List<ExpenditureReimbursementPayDto> erpds1 = expenditureReimbursementPayService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementPayService.removeBatchByList(erpds1);
        // payees
        List<ExpenditureReimbursementPayeeDto> erpds2 = expenditureReimbursementPayeeService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementPayeeService.removeBatchByList(erpds2);
        // files
        List<ExpenditureReimbursementFileDto> erfds = expenditureReimbursementFileService.listByField("expenditureReimbursementId", id);
        expenditureReimbursementFileService.removeBatchByList(erfds);
        return result;
    }

    @Override
    public Page<ExpenditureReimbursementDto> queryExpenditureReimbursement(Page<ExpenditureReimbursementDto> pager, ExpenditureReimbursementReq req, ExpenditureAccountType accountType) {
        ExpenditureReimbursementDto c = BeanUtil.copyProperties(req, ExpenditureReimbursementDto.class);
        ExpenditureReimbursementPayDto c1 = new ExpenditureReimbursementPayDto();
        c1.setPayType(req.getPayType());
        c1.setSettleType(req.getSettleType());
        c1.setPayAccount(req.getPayAccount());
        c1.setPay(req.getPay());
        c1.setAmount(req.getAmount());
        c1.setPaySummary(req.getPaySummary());
        ExpenditureReimbursementPayeeDto c2 = new ExpenditureReimbursementPayeeDto();
        c2.setPayeeType(req.getPayeeType());
        c2.setExpenditureProceedsId(req.getExpenditureProceedsId());
        c2.setProceedsCompany(req.getProceedsCompany());
        c2.setProceedsBank(req.getProceedsBank());
        c2.setProceedsAccount(req.getProceedsAccount());
        c2.setExpenditureBusinessCardId(req.getExpenditureBusinessCardId());
        c2.setBusinessCardName(req.getBusinessCardName());
        c2.setBusinessCardBank(req.getBusinessCardBank());
        c2.setBusinessCardAccount(req.getBusinessCardAccount());
        c2.setPayeeSummary(req.getPayeeSummary());
        final Set<Long> ids1 = new HashSet<>();
        final Set<Long> ids2 = new HashSet<>();
        boolean all1 = true;
        boolean all2 = true;
        if (StrUtil.isNotBlank(c1.getPayType())
                || StrUtil.isNotBlank(c1.getSettleType())
                || StrUtil.isNotBlank(c1.getPayAccount())
                || StrUtil.isNotBlank(c1.getPay())
                || c1.getAmount() != null
                || StrUtil.isNotBlank(c1.getPaySummary()) || accountType != null) {
            if (accountType != null) {
                ExpenditureAccountDto acc = new ExpenditureAccountDto();
                acc.setAccountType(accountType.getKey());
                acc.setState(CommonEnableDisable.enabled.getKey());
                List<ExpenditureAccountDto> accounts = expenditureAccountService.listByField("accountType", accountType.getKey());
                List<String> accountIds = accounts.stream().map(expenditureAccountDto -> expenditureAccountDto.getId().toString()).collect(Collectors.toList());
                if (StrUtil.isNotBlank(c1.getPayAccount()) && !accountIds.contains(c1.getPayAccount())) {
                    Page<ExpenditureReimbursementDto> r = new Page<>();
                    r.setRecords(Collections.emptyList());
                    r.setTotal(0);
                    return r;
                }
                if (StrUtil.isBlank(c1.getPayAccount())) {
                    c1.setPayAccount(CollUtil.join(accountIds, ","));
                }
            }
            log.debug("ExpenditureReimbursementPayDto c1:" + JSONUtil.toJsonStr(c1));
            List<ExpenditureReimbursementPayDto> list = expenditureReimbursementPayService.list(c1);
            all1 = false;
            CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureReimbursementPayDto>) (v, i) -> ids1.add(v.getExpenditureReimbursementId()));
        }

        if (StrUtil.isNotBlank(c2.getPayeeType())
                || c2.getExpenditureProceedsId() != null
                || StrUtil.isNotBlank(c2.getProceedsCompany())
                || StrUtil.isNotBlank(c2.getProceedsBank())
                || StrUtil.isNotBlank(c2.getProceedsAccount())
                || c2.getExpenditureBusinessCardId() != null
                || StrUtil.isNotBlank(c2.getBusinessCardName())
                || StrUtil.isNotBlank(c2.getBusinessCardBank())
                || StrUtil.isNotBlank(c2.getBusinessCardAccount())
                || StrUtil.isNotBlank(c2.getPayeeSummary())) {
            log.debug("ExpenditureReimbursementPayeeDto c2:" + JSONUtil.toJsonStr(c2));
            List<ExpenditureReimbursementPayeeDto> list = expenditureReimbursementPayeeService.list(c2);
            all2 = false;
            CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureReimbursementPayeeDto>) (v, i) -> ids2.add(v.getExpenditureReimbursementId()));
        }
        log.debug("pay all1:" + all1);
        log.debug("payee all2:" + all2);
        QueryWrapper<ExpenditureReimbursementPo> queryWrapper = this.buildWrapper(c);
        if (!all1 && CollUtil.isEmpty(ids1)) {
            Page<ExpenditureReimbursementDto> r = new Page<>();
            r.setRecords(Collections.emptyList());
            r.setTotal(0);
            return r;
        }
        if (!all2 && CollUtil.isEmpty(ids2)) {
            Page<ExpenditureReimbursementDto> r = new Page<>();
            r.setRecords(Collections.emptyList());
            r.setTotal(0);
            return r;
        }
        log.debug("pay ids1:" + ids1);
        log.debug("payee ids2:" + ids2);

        if (!all1 || !all2) {
            Collection<Long> ids = null;
            if (CollUtil.isNotEmpty(ids1) && CollUtil.isNotEmpty(ids2)) {
                ids = CollUtil.intersection(ids1, ids2);
            } else if (CollUtil.isNotEmpty(ids1)) {
                ids = ids1;
            } else if (CollUtil.isNotEmpty(ids2)) {
                ids = ids2;
            }
            log.debug("ids:" + ids);
            if (CollUtil.isEmpty(ids)) {
                Page<ExpenditureReimbursementDto> r = new Page<>();
                r.setRecords(Collections.emptyList());
                r.setTotal(0);
                return r;
            }
            queryWrapper.in("id", ids);
        }
        Page<ExpenditureReimbursementPo> page = PageUtil.copyPage(pager, ExpenditureReimbursementPo.class);
        Page<ExpenditureReimbursementPo> data = this.getMapper().selectPage(page, queryWrapper);
        return PageUtil.copyPage(data, this.getDtoClass());
    }

}
